import { Controller, Get, Post, Body, Query, HttpException, HttpStatus, UnauthorizedException, ParseIntPipe, BadRequestException, DefaultValuePipe, Req, UseInterceptors, UploadedFile } from '@nestjs/common';
import { UserService } from './user.service';
import { ApiBearerAuth, ApiExcludeEndpoint, ApiQuery, ApiQueryOptions, ApiResponse, ApiTags } from '@nestjs/swagger';
import { RegisterUserDto } from './dto/register-user.dto';
import { EmailService } from '../email/email.service';
import { RedisService } from '../redis/redis.service';
import { EmailDto } from './dto/email.dto';
import { LoginUserDto } from './dto/login-user.dto';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { RequireLogin, UserInfo } from '../custom.decorator';
import { UserDetailVo } from './vo/user-info.vo';
import { UpdateUserPasswordDto } from './dto/update-user-password.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { generateParseIntPipe } from '../utils';
import { LoginUserVo } from './vo/login-user.vo';
import { FileInterceptor } from '@nestjs/platform-express';
import * as path from 'path';
import { storage } from './my-file-storage';

@ApiTags('用户管理模块')
@ApiBearerAuth()
@Controller('user')
export class UserController {
  constructor(
    private readonly userService: UserService,
    private emailService: EmailService,
    private redisService: RedisService,
    private jwtService: JwtService,
    private configService: ConfigService
  ) { }


  //用户信息
  @Get('info')
  @RequireLogin()
  async info(@UserInfo('userId') userId: number) {
    const user = await this.userService.findUserDetailById(userId);

    const vo = new UserDetailVo();
    vo.id = user.id;
    vo.username = user.username;
    vo.nickName = user.nickName;
    vo.email = user.email;
    vo.phoneNumber = user.phoneNumber;
    vo.headPic = user.headPic;
    vo.createTime = user.createTime;
    vo.isFrozen = user.isFrozen;

    return vo;
  }

  //用户列表
  @Get('list')
  @RequireLogin()
  @ApiQuery({ name: 'pageNo', type: Number, description: '页码', example: 1, minimum: 1 } as ApiQueryOptions)
  @ApiQuery({ name: 'pageSize', type: Number, description: '每页数量', example: 10 })
  @ApiQuery({ name: 'username', type: String, required: false, })
  @ApiQuery({ name: 'nickName', type: String, required: false })
  @ApiQuery({ name: 'email', type: String, required: false })
  async list(
    @Query('pageNo', new DefaultValuePipe(1), generateParseIntPipe('pageNo')) pageNo: number,
    @Query('pageSize', new DefaultValuePipe(2), generateParseIntPipe('pageSize')) pageSize: number,
    @Query('username') username: string,
    @Query('nickName') nickName: string,
    @Query('email') email: string
  ) {
    return await this.userService.findUsers(username, nickName, email, pageNo, pageSize);
  }





  //修改密码
  @RequireLogin()
  @Post(['update_password', 'admin/update_password'])
  async updatePassword(@Body() passwordDto: UpdateUserPasswordDto) {
    return await this.userService.updatePassword(passwordDto);
  }
  //修改用户信息
  @Post(['update', 'admin/update'])
  @RequireLogin()
  async update(@UserInfo('userId') userId: number, @Body() updateUserDto: UpdateUserDto) {
    return await this.userService.update(userId, updateUserDto);
  }
  //上传头像
  @Post('upload')
  @UseInterceptors(FileInterceptor('file', {
    dest: 'uploads',
    storage: storage,
    limits: {
      fileSize: 1024 * 1024 * 3
    },
    fileFilter(req, file, callback) {
      const extname = path.extname(file.originalname);
      if (['.png', '.jpg', '.gif'].includes(extname)) {
        callback(null, true);
      } else {
        callback(new BadRequestException('只能上传图片'), false);
      }
    }
  }))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log('file', file);
    return file.path;
  }

  //冻结用户操作
  @Get('freeze')
  async freeze(@Query('id') userId: number) {
    await this.userService.freezeUserById(userId);
    return 'success';
  }





  //登录并存储信息进jwt
  @Post('login')
  @ApiResponse({ status: HttpStatus.OK, description: '返回格式 :', type: LoginUserVo })
  async userLogin(@Body() loginUser: LoginUserDto) {
    //如果不加await,vo就会变成一个Promise对象,而不是期待的返回值
    const vo = await this.userService.login(loginUser, false)

    vo.accessToken = this.jwtService.sign({
      userId: vo.userInfo.id,
      username: vo.userInfo.username,
      email: vo.userInfo.email,
      roles: vo.userInfo.roles,
      permissions: vo.userInfo.permissions
    }, { expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m' });

    vo.refreshToken = this.jwtService.sign({
      userId: vo.userInfo.id
    }, { expiresIn: this.configService.get('jwt_refresh_token_expres_time') || '7d' });

    return vo;
  }
  //刷新 token
  @Get('refresh')
  async refresh(@Query('refreshToken') refreshToken: string) {

    try {
      const data = this.jwtService.verify(refreshToken);
      const user = await this.userService.findUserById(data.userId, false);

      const access_token = this.jwtService.sign({
        userId: user.id,
        username: user.username,
        email: user.email,
        roles: user.roles,
        permissions: user.permissions
      }, {
        expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m'
      });

      const refresh_token = this.jwtService.sign({
        userId: user.id
      }, {
        expiresIn: this.configService.get('jwt_refresh_token_expres_time') || '7d'
      });

      return {
        access_token,
        refresh_token
      }
    } catch (e) {
      throw new UnauthorizedException('token 已失效，请重新登录');
    }
  }
  //登录并存储信息进jwt（admin）
  @Post('admin/login')
  @ApiResponse({ status: HttpStatus.OK, description: '返回格式 :', type: LoginUserVo })
  async adminLogin(@Body() loginUser: LoginUserDto) {
    //如果不加await,vo就会变成一个Promise对象,而不是期待的返回值
    const vo = await this.userService.login(loginUser, true)

    vo.accessToken = this.jwtService.sign({
      userId: vo.userInfo.id,
      username: vo.userInfo.username,
      email: vo.userInfo.email,
      roles: vo.userInfo.roles,
      permissions: vo.userInfo.permissions
    }, { expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m' });

    vo.refreshToken = this.jwtService.sign({
      userId: vo.userInfo.id
    }, { expiresIn: this.configService.get('jwt_refresh_token_expres_time') || '7d' });

    return vo;
  }
  //刷新 token（admin）
  @Get('admin/refresh')
  async adminRefresh(@Query('refreshToken') refreshToken: string) {
    try {
      const data = this.jwtService.verify(refreshToken);
      const user = await this.userService.findUserById(data.userId, true);

      const access_token = this.jwtService.sign({
        userId: user.id,
        username: user.username,
        email: user.email,
        roles: user.roles,
        permissions: user.permissions
      }, { expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m' });

      const refresh_token = this.jwtService.sign({
        userId: user.id
      }, { expiresIn: this.configService.get('jwt_refresh_token_expres_time') || '7d' });

      return {
        access_token,
        refresh_token
      }
    } catch (e) {
      throw new UnauthorizedException('token 已失效，请重新登录');
    }
  }






  //获取二维码
  @Get('register-captcha')
  async captcha(@Query() emailDto: EmailDto) {
    const email = emailDto.email;
    //先判断是否注册
    const finduser = await this.userService.finduserWithEmail(email);
    if (finduser) { throw new HttpException('该用户已注册', HttpStatus.BAD_REQUEST); }

    const code = Math.random().toString().slice(2, 8);
    await this.redisService.set(`captcha_${email}`, code, 5 * 60);

    await this.emailService.sendMail({
      to: email,
      subject: '注册验证码',
      html: `<p>你的注册验证码是 ${code}</p>`
    });
    return '发送成功';
  }
  //获取验证码(修改密码)
  @Get('update_password/captcha')
  async updatePasswordCaptcha(@Query() emailDto: EmailDto) {
    const email = emailDto.email;
    //先判断是否注册
    const finduser = await this.userService.finduserWithEmail(email);
    if (!finduser) { throw new HttpException('请输入正确的邮箱', HttpStatus.BAD_REQUEST); }

    const code = Math.random().toString().slice(2, 8);
    await this.redisService.set(`update_password_captcha_${email}`, code, 10 * 60);

    await this.emailService.sendMail({
      to: email,
      subject: '更改密码验证码',
      html: `
      <style>
          .email-template {
            font-family: Arial, sans-serif;
            padding: 20px;
            margin-bottom: 20px;
          }
          
          .email-template h1 {
            text-align: center;
            color: #333333;
          }
          
          .email-template p {
            text-align: justify;
            color: #666666;
          }
          
          .email-template h2 {
            font-size: 20px;
            color: #333333;
            font-weight: bold;
          }
      </style>
      <div class="email-template">
        <p>欢迎使用会议室预订系统！这是您请求的验证码。</p>
        <h2>更改密码验证码：${code}</h2>
        <p>请尽快在规定时间内完成更改。</p>
        <p>如果您没有发起更改密码的操作，请忽略此邮件。</p>
        <p>感谢您的配合。</p>
      </div>
      `
    });
    return '发送成功';
  }
  //获取验证码(修改用户信息)
  @Get('update/captcha')
  @RequireLogin()
  @ApiBearerAuth()
  async updateCaptcha(@UserInfo('email') email: string) {
    //先判断是否注册
    const finduser = await this.userService.finduserWithEmail(email);
    if (!finduser) { throw new HttpException('错误操作,请重试', HttpStatus.BAD_REQUEST); }

    const code = Math.random().toString().slice(2, 8);
    await this.redisService.set(`update_user_captcha_${email}`, code, 10 * 60);

    await this.emailService.sendMail({
      to: email,
      subject: '更改用户信息验证码',
      html: `<p>你的验证码是 ${code}</p>`
    });
    return '发送成功';
  }
  //用户注册 
  @Post('register')
  register(@Body() registerUser: RegisterUserDto) {
    return this.userService.register(registerUser);
  }
  
  //初始化数据
  // 一定要注意上面的:id要做类型限制,否则会匹配失败
  // @ApiExcludeEndpoint() 不显示在swagger
  @Get("init-data") 
  async initData() { 
    await this.userService.initData(); 
    return 'done';
  }

}
